Add Xilinx Zynq-7000 (ZC702) wolfBoot port#770
Open
dgarske wants to merge 1 commit into
Open
Conversation
Contributor
There was a problem hiding this comment.
Pull request overview
This PR adds an initial wolfBoot port for Xilinx Zynq-7000 on the ZC702 board, extending the codebase with a new ARMv7-A / Cortex-A9 target that boots via the Xilinx FSBL, verifies images from QSPI, and chain-loads a staged payload from DDR.
Changes:
- Adds a new
zynq7000target across the HAL, startup code, linker scripts, and build system for FSBL-loaded Cortex-A9 boot. - Introduces a Zynq-7000 QSPI/UART HAL, RAM-boot configuration, and a minimal test application for bring-up validation.
- Documents the target, JTAG workflow, QSPI layout, and adds helper scripts for XSDB/bootgen usage.
Reviewed changes
Copilot reviewed 14 out of 14 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
tools/scripts/zc702/zc702_qspi.bif |
Adds a bootgen BIF template for packaging FSBL + wolfBoot into BOOT.BIN. |
tools/scripts/zc702/jtag_load.tcl |
Adds an XSDB script for JTAG bring-up by running FSBL and loading wolfboot.elf into DDR. |
test-app/app_zynq7000.c |
Adds a minimal bare-metal ZC702 test app that prints a boot banner and heartbeat on UART1. |
test-app/Makefile |
Wires the new target into test-app builds with the ARM32 startup object and target linker script. |
test-app/ARM-zynq7000.ld |
Adds the linker script for the staged Zynq-7000 test application in DDR. |
src/boot_zynq7000_start.S |
Adds Zynq-7000-specific ARMv7-A startup, vector setup, stack initialization, and early CPU state handling. |
src/boot_arm32.c |
Adjusts ARM32 inline assembly immediate syntax used during chain-load handoff. |
hal/zynq7000.ld |
Adds the wolfBoot linker script for execution from DDR at the FSBL handoff address. |
hal/zynq7000.h |
Defines Zynq-7000 register maps and bitfields for UART, QSPI, and related peripherals. |
hal/zynq7000.c |
Implements the new Zynq-7000 HAL, including UART, QSPI external flash access, and boot-preparation logic. |
docs/Targets.md |
Documents the new ZC702 target, configuration, memory map, JTAG flow, and expected output. |
config/examples/zynq7000.config |
Adds an example configuration for ECC256/SHA256 RAM-boot from external QSPI flash. |
arch.mk |
Adds target selection and Cortex-A9-specific compiler/object settings for zynq7000. |
Makefile |
Includes the new target in the default main build outputs. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
267e3d7 to
4f7a802
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This PR adds an upstream wolfBoot port for the AMD/Xilinx Zynq-7000 SoC (Cortex-A9, ARMv7-A), verified end-to-end on the ZC702 Evaluation Kit. The port covers QSPI cold-boot, SD-card cold-boot, JTAG-loaded development, and signed Linux / U-Boot / bare-metal payload chain-loading from a single
TARGET=zynq7000build target.It also generalises the existing ARMv7-A startup file so SAMA5D3 (Cortex-A5) and Zynq-7000 (Cortex-A9) now share one path through
src/boot_arm32_start.Sandsrc/boot_arm32.c.A late simplification removes the
LINUX_PAYLOAD=1config knob that earlier revisions of this PR required, and hardens the legacy U-Boot uImage header detection with a CRC32 check. The result is a single config that "just works" for both bare-metal and Linux payloads, with no per-deployment switch.What's in the port
New files
hal/zynq7000.c,hal/zynq7000.h,hal/zynq7000.ld-- HAL: UART, GPTimer, QSPI (XQspiPs N25Q128), Arasan v2.0 SDHCI hooks, cache teardown.config/examples/zynq7000.config-- QSPI deployment (BootROM -> FSBL -> wolfBoot -> kernel/app).config/examples/zynq7000_sdcard.config-- SD-card deployment with MBR layout that the Zynq-7000 BootROM accepts (FAT32-LBA + Active flag in p1).test-app/app_zynq7000.c,test-app/ARM-zynq7000.ld-- bare-metal banner + heartbeat for end-to-end verification.tools/scripts/zynq7000/*--prepare_linux.sh,prepare_sdcard.sh,jtag_load.tcl,zynq7000_qspi.bif.docs/Targets.md-- ZC702 bring-up walkthrough, QSPI / SD / JTAG paths, Linux recipe, ZynqMP comparison.Touched
src/boot_arm32.c-- always emits the ARM Linux boot ABI whenMMU=1(r0=0, r1=~0, r2=DTB, r3=0). Bare-metal payloads ignorer0..r3, so one ABI covers both payload types. No more per-targetLINUX_PAYLOADswitch needed.src/boot_arm32_start.S-- generalised ARMv7-A startup (VBAR, per-mode stacks, cache invalidate, async-abort enable). Replaces what was a Cortex-A5-specific file; SAMA5D3 now uses the same path.src/update_ram.c-- legacy U-Boot uImage header detection now validates magic + header CRC32 + payload size, dropping the joint false-positive probability from ~2^-32 to ~2^-64 and matching U-Boot's own mkimage/bootm validation. Reusesgpt_crc32_*fromsrc/gpt.c.arch.mk-- newCORTEX_A9=1block underTARGET=zynq7000.WOLFBOOT_UBOOT_LEGACYis now always-on for zynq7000 (matching sibling ZynqMP / Versal targets); the previousLINUX_PAYLOAD=1gate is gone.src/gpt.ois now linked for every Cortex-A9 build and every AARCH64 RAM-update build (where the hardened uImage check uses it).Three boot paths, one config flavour
The QSPI config is the primary path.
MMU=1 ELF=1are baked in by default so the same wolfBoot image can chain-load a signed bare-metal.bin, a signed U-Boot, or a signed LinuxzImage. Bare-metal payloads ignore the ARM Linux ABI registers wolfBoot passes in. Cost vs. a strictly bare-metal build is about 5 KB of unused FDT/MMU code (31 KB -> 36 KB).For SD-card boot the layout is pure MBR (FAT32-LBA + Active in p1 for BOOT.BIN; raw Linux partitions p2/p3 for signed BOOT_A / BOOT_B). The BootROM (UG821 ch.6.3) refuses the GPT layout used on ZynqMP / Versal.
src/disk.c's MBR-fallback handles this.For Linux from SD we default to
CONFIG_ARM_APPENDED_DTB(DTB concatenated to zImage and signed as one image), since the ARMv7 zImage decompressor on this kernel/load combo does not always preserver2across the transition to decompressedhead.S. The raw-DTB-from-partition path viaPART_DTS_BOOTremains plumbed for kernels that handler2correctly.Booting Linux through wolfBoot
Verified end-to-end with stock Xilinx Linux 6.1.70 (
xilinx_zynq_defconfig) andzynq-zc702.dtb. wolfBoot reads the signed kernel out of QSPI / SD, verifies it, copies it to DDR at0x10000000, disables MMU and caches, andbx's into the zImage decompressor. Linux brings up both Cortex-A9 cores, the L2C-310, and the full SMP init; it panics only when no rootfs is supplied (expected for the proof-of-concept).Hardened legacy uImage detection
The wolfBoot legacy uImage strip (
WOLFBOOT_UBOOT_LEGACYinsrc/update_ram.c) previously matched on magic only -- one 32-bit comparison againstUBOOT_IMG_HDR_MAGIC. That left a ~1-in-2^32 false-positive window for non-uImage payloads whose first 4 bytes happened to collide with the magic.This PR replaces the magic-only check with a structural validator that requires all of:
ih_magic == 0x27051956ih_size(big-endian) is> 0and fits inside the signed image (<= total - 64)ih_hcrcmatches the CRC32 of the 64-byte header with thehcrcfield treated as zero -- same algorithm (reflected CRC-32, poly0xEDB88320) and same field semantics that U-Boot'smkimage/bootmuseJoint collision probability drops from ~2^-32 to ~2^-64. The CRC32 implementation is the existing
gpt_crc32_*helpers insrc/gpt.c, so no new code is added beyond the validator itself.The hardening covers all targets that enable
WOLFBOOT_UBOOT_LEGACY: zynq7000 (this PR), ZynqMP, and Versal.Build verification
All four affected configurations build cleanly with no warnings or errors:
zynq7000.config(QSPI)zynq7000_sdcard.configzynqmp.configsama5d3.configThe SAMA5D3 regression confirms the non-MMU branch of the generalised
do_boot(used by targets withoutMMU=1) is unaffected by the always-Linux-ABI change.Known limitations / follow-ups
r2quirk -- the appended-DTB path is the documented default. The raw-DTB-from-partition path works for decompressors that preserver2; needs upstream Linux investigation before we can recommend it generally.src/sdhci.cneeds an explicit DAT-line reset between transfers before we can raise the post-init clock. Sufficient for boot-time loading today (~3 MB/s).hal_prepare_boot()with an L2x0 clean-invalidate + disable.Why a separate port from ZynqMP?
Despite the shared name, the two SoCs differ in nearly every block wolfBoot interacts with:
hal/zynq.c)hal/zynq7000.c)XQspiPsu)XQspiPs)bootgen -archzynqmpzynqWith this PR the entire AMD/Xilinx adaptive-SoC lineup -- Zynq-7000, ZynqMP, Versal -- builds from a common wolfBoot codebase.